package com.gxa.weixing.core.util;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import org.apache.poi.hssf.usermodel.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.List;

/**
 * 定义一个导出的工具类
 *
 * @author YXQ
 * @date 2021/9/25 10:02
 */
public class ExportUtil<T> {
    /**
     * 导出数据的封装操作--通过POI
     *
     * @param list      导出的全数据集合
     * @param tClass    获取反射的类
     * @param fileName  文件名
     * @param sheetName 表名
     * @param headers   表头的数据:例如{"第一列的表头名字","第二列的表头"..."第n列的表头"}
     * @param response  最后给前端响应的响应头信息
     * @param <T>       泛型
     * @throws Exception 异常
     */
    public static <T> void poiExport(List<T> list, Class<T> tClass, String fileName, String sheetName
            , String[] headers, HttpServletResponse response) throws Exception {
        // 创建工作簿对象(excel对象)
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 创建工作表
        HSSFSheet sheet = workbook.createSheet(sheetName);
        // 创建一个行对象, 作为表头
        HSSFRow row = sheet.createRow(0);
        for (int i = 0; i < headers.length; i++) {
            // 在行中添加单元格
            HSSFCell cell = row.createCell(i);
            // 先把文字转换成标准的富文本格式
            HSSFRichTextString text = new HSSFRichTextString(headers[i]);
            // 把字段名添加到表头行上
            cell.setCellValue(text);
        }
        // 添加数据行:
        int rowNum = 1;
        // 遍历集合获取集合中的每一个字段
        for (T item : list) {
            // 工作行
            HSSFRow dataRow = sheet.createRow(rowNum);
            // 得到全部字段的数组
            Field[] declaredFields = tClass.getDeclaredFields();
            // 遍历数组
            for (int i = 0; i < declaredFields.length; i++) {
                // 获取字段
                String fieldName = declaredFields[i].getName();
                // 首字母大写
                char first = Character.toUpperCase(fieldName.charAt(0));
                // 拼接方法名
                String methodName = "get" + first + fieldName.substring(1);
                // 通过反射过去方法
                Method declaredMethod = tClass.getDeclaredMethod(methodName);
                // 反射执行方法-->这里获取get方法的返回值
                Object invoke = declaredMethod.invoke(item);
                // 写入表格中
                dataRow.createCell(i).setCellValue(invoke.toString());
            }
            rowNum++;
        }
        // 将文件名中的中文部分被URL编码后的内容进行解析, 最终还是显示为中文状态
        fileName = URLEncoder.encode(fileName, "utf-8").replaceAll("\\+", "%20");
        // 返回给前端下载
        response.setContentType("application/octet-stream");
        // 告诉浏览器，以附件方式打开，而不是在页面上浏览
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        // 刷新流
        response.flushBuffer();
        // 写入文件
        workbook.write(response.getOutputStream());
    }

    /**
     * 通过easyExcel(语雀)实现导出
     *
     * @param list      待导出的集合
     * @param tClass    待导出的类
     * @param fileName  文件名
     * @param sheetName 表格的名字
     * @param response  前端响应信息
     * @param <T>       泛型
     * @throws IOException 异常
     */
    public static <T> void easyExcelExport(List<T> list, Class<T> tClass, String fileName, String sheetName
            , HttpServletResponse response) throws IOException {
        // 声明输出流对象
        ServletOutputStream out;
        // 接收输出流对象
        out = response.getOutputStream();
        // 编辑生成表格文件的文件名
        String excelName = fileName + ".xlsx";
        // 设置请求头信息,告诉前端以附件形式下载
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(excelName, "utf-8"));
        // 调用语雀的写表格方法
        EasyExcelFactory.write(out, tClass).
                registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet(sheetName).doWrite(list);
        if (out != null) {
            // 关闭输出流对象
            out.close();
        }
    }
}
